API Gateway REST API + Cognito User Pool Authorizer + Lambda Functionな構成をAWS CDK v2で構築してみた
こんにちは、CX事業本部 IoT事業部の若槻です。
前回に引き続き、今回もAWS CDK v2の肩慣らしをしていこうと思います。
今回は、API Gateway REST API + Cognito User Pool Authorizer + Lambda Functionな構成をAWS CDK v2で構築してみました。
環境
- react@18.0.0
- typescript@4.6.3
やってみた
このような構成を構築してみます。
実装
CDK Stackのコードは次のようになります。Lambda Functionコードの参照はReference project architectureを使用しています。
import { Construct } from 'constructs'; import { Stack, StackProps, RemovalPolicy, aws_cognito, aws_lambda_nodejs, aws_apigateway, } from 'aws-cdk-lib'; export interface AwsCdkV2AppStackProps extends StackProps { callbackUrls: string[]; logoutUrls: string[]; domainPrefix: string; } export class AwsCdkV2AppStack extends Stack { constructor(scope: Construct, id: string, props: AwsCdkV2AppStackProps) { super(scope, id, props); // User Pool const userPool = new aws_cognito.UserPool(this, 'userPool', { userPoolName: 'testUserPool', selfSignUpEnabled: false, standardAttributes: { email: { required: true, mutable: true }, phoneNumber: { required: false }, }, signInCaseSensitive: false, autoVerify: { email: true }, signInAliases: { email: true }, accountRecovery: aws_cognito.AccountRecovery.EMAIL_ONLY, removalPolicy: RemovalPolicy.DESTROY, }); // User Pool Domain userPool.addDomain('domain', { cognitoDomain: { domainPrefix: props.domainPrefix }, }); //今回はログインUIを使わないので無くてもOK // User Pool Client userPool.addClient('client', { userPoolClientName: 'testUserPoolClient', generateSecret: false, oAuth: { callbackUrls: props.callbackUrls, logoutUrls: props.logoutUrls, flows: { authorizationCodeGrant: true }, scopes: [ aws_cognito.OAuthScope.EMAIL, aws_cognito.OAuthScope.OPENID, aws_cognito.OAuthScope.PROFILE, ], }, authFlows: { adminUserPassword: true }, //cognitoIdp:adminInitiateAuth APIでユーザートークンを取得可能にする }); // Lambda Function const lambdaFunc = new aws_lambda_nodejs.NodejsFunction(this, 'lambdaFunc'); // Cognito Authorizer const cognitoAuthorizer = new aws_apigateway.CognitoUserPoolsAuthorizer( this, 'cognitoAuthorizer', { authorizerName: 'CognitoAuthorizer', cognitoUserPools: [userPool], } ); // Rest API const restApi = new aws_apigateway.RestApi(this, 'restApi'); // Rest API Resource/Method restApi.root .addResource('data') .addMethod('GET', new aws_apigateway.LambdaIntegration(lambdaFunc), { authorizer: cognitoAuthorizer, }); } }
Lambda Functionのコードは次のようになります。固定のデータを200 OK
で返すだけです。
exports.handler = async () => { const response = { statusCode: 200, body: JSON.stringify({ greeting: 'Hello from Lambda!' }), }; return response; };
cdk deploy
で構成をデプロイします。OutputでREST APIのエンドポイントのURI(`https://{apiId}.execute-api.ap-northeast-1.amazonaws.com/prod/`)が表示されるので控えます。
動作確認
先程控えたエンドポイントのURIを使用してdata
リソースのURLを変数に指定します。
$ endpointUri=<endpointUri> $ dataResourceUri=${endpointUri}data
作成されたUser Poolにユーザーを作成します。
ユーザーのID Token取得に必要な情報を変数に指定します。
$ userName=<userName> $ userPassword=<userPassword> $ userPoolId=<userPoolId> $ clientId=<userPoolClientId>
cognitoIdp:adminInitiateAuth APIを使用してユーザーのID Tokenを取得します。
$ idToken=$(aws cognito-idp admin-initiate-auth \ --user-pool-id ${userPoolId} \ --client-id ${clientId} \ --auth-flow "ADMIN_USER_PASSWORD_AUTH" \ --auth-parameters USERNAME=${userName},PASSWORD=${userPassword} \ --query "AuthenticationResult.IdToken" \ --output text)
リソースURIにID Tokenを使用してGETリクエストすると、認証が成功すればLambda Functionからデータが返されます。
$ curl -H "Authorization: ${idToken}" ${dataResourceUri} {"greeting":"Hello from Lambda!"}
少しハマったところ
トークン違いによるUnauthorizedエラー
Authorization
ヘッダーに間違えてAccess Tokenを指定して401 Unauthorized
エラーとなった。
正しくはID Tokenを指定します。
HTTP APIのHigh Level ConstructはまだExperimental
APIとしてaws_apigatewayv2
(HTTP API)を使いたかったのですが、CDK v2のHigher level constructsがまだExperimentalでした。
なのでaws_apigateway
(REST API)を今回は使いました。
おわりに
API Gateway REST API + Cognito User Pool Authorizer + Lambda Functionな構成をAWS CDK v2で構築してみました。
よくある構成だと思うので、今後よく使うテンプレートとなりそうです。ただHandler Fileの参照で使用したReference project architectureは少々挑戦的だったので、場合によってはEntryによる参照を使うかもしれません。
参考
- [AWS CDK] API Gateway(REST API)のCORSの動作を確認してみた | DevelopersIO
- AWS CDKでCognito認証されたAPI Gateway(HTTP API)を構築する | DevelopersIO
- API Gateway→Lambdaをcurlでテストする - Qiita
- AWS CLIでCognitoユーザーのアクセストークン/IDトークンを取得する | DevelopersIO
- npm scriptsから実行してCognitoユーザーのIDトークンを取得できるスクリプト(TypeScript)を作ってみた | DevelopersIO
以上